package com.zmn.oms.third.taobao.msghandler.impl;

import com.alibaba.fastjson.JSON;
import com.github.ltsopensource.core.domain.Job;
import com.google.common.collect.Lists;
import com.taobao.api.internal.tmc.Message;
import com.taobao.api.internal.tmc.MessageStatus;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.dubbo.interfaces.area.AreaListRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.manager.lts.interfaces.task.TaskManager;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.interfaces.baidumap.BaiduMapBService;
import com.zmn.oms.business.interfaces.mapping.MapCityTmallService;
import com.zmn.oms.business.interfaces.tmall.OrderTmallExtendBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.constant.RedisKeyConsts;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.manager.utils.TaskConsts;
import com.zmn.oms.model.bo.order.OrderBO;
import com.zmn.oms.model.dto.baidumap.LngLatLocation;
import com.zmn.oms.model.dto.order.proxy.CancelOrderDTO;
import com.zmn.oms.model.dto.order.proxy.CreateOrderDTO;
import com.zmn.oms.model.dto.product.ChannelProductMapDTO;
import com.zmn.oms.model.dto.product.OrderProductDTO;
import com.zmn.oms.model.dto.tmall.OrderTmallExtendDTO;
import com.zmn.oms.model.entity.map.MapCityTmall;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.vo.work.ZsOrderWorkVO;
import com.zmn.oms.third.base.util.ThirdOrderUtil;
import com.zmn.oms.third.taobao.TaobaoMapper;
import com.zmn.oms.third.taobao.TaobaoTmcConstants;
import com.zmn.oms.third.taobao.TaobaoTmcUtil;
import com.zmn.oms.third.taobao.dto.TmcOrderDTO;
import com.zmn.oms.zmn.business.interfaces.product.ProductMappingBService;
import com.zmn.oms.zmn.business.interfaces.proxy.ProxyOrderBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
import com.zmn.pay.common.constant.PayConsts;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.regex.Pattern;

/**
 * 类描述：订单消息处理器
 *
 * @author LiangHailong
 * @date 2019/07/24 17:35
 */
@Component("orderTmcMsgHandler")
public class OrderTmcMsgHandler extends TmcMsgHandlerBase {
    private static final Logger logger = LoggerFactory.getLogger(OrderTmcMsgHandler.class);

    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected AreaListRemoteService areaListRemoteService;
    @Autowired
    private ProxyOrderBService proxyOrderBService;
    @Autowired
    private MapCityTmallService mapCityTmallService;
    @Autowired
    private OrderTmallExtendBService orderTmallExtendBService;
    @Autowired
    private WorkFlowContextBService workFlowContextBService;
    @Autowired
    private BaiduMapBService baiduMapBService;
    @Autowired
    private ProductMappingBService productMappingBService;
    @Autowired
    TaskManager taskManager;
    @Autowired
    RedisManager redisManager;

    /**
     * 处理订单消息
     * @param message
     * @param status
     */
    @Override
    public void procMsg(Message message, MessageStatus status) {
        try {
            TmcOrderDTO tmcOrderDTO = TaobaoTmcUtil.parseMessageContent(message.getContent(), TmcOrderDTO.class);

            String serviceCode = tmcOrderDTO.getServiceCode();
            if (TaobaoTmcConstants.SERVICE_SEND_AND_INSTALL.equals(serviceCode)
                    || TaobaoTmcConstants.SERVICE_TV_INSTALL.equals(serviceCode)
                    || TaobaoTmcConstants.SERVICE_APPLIANCE_INSTALL.equals(serviceCode)) {
                // 天猫B端安装订单消息
                procMsg4TmallBusiness(tmcOrderDTO, message);
            }
            else {
                // 天猫天猫勤鸽店（无忧购）订单消息
                procMsg4TmallQG(tmcOrderDTO, message);
            }
        } catch (Exception e) {
            logger.info("【{}-消息-订单】消息处理失败，触发消息重发！ErrorMsg:[{}]",
                    TaobaoTmcConstants.NAME_TMALL, e.getMessage());
            logger.error(e.getMessage(), e);
            status.fail(); // 消息处理失败回滚，服务端需要重发
        }
    }

    /**
     * 处理天猫勤鸽店（无忧购）订单消息
     */
    private void procMsg4TmallQG(TmcOrderDTO tmcOrderDTO, Message message) throws Exception {
        /*                  分析推送过来的订单的状态                       */
        /* 当订单信息（状态）发生变化时，淘宝会将最新订单信息推送过来（包括   */
        /* 通过接口给淘宝同步订单状态引起的订单状态改变），所以需依靠状态字段 */
        /* （taskStatus）来区分出该订单消息的业务类型（主要提取新单消息和顾客 */
        /* 主动取消订单消息）                                              */
        Integer taskStatus = tmcOrderDTO.getTaskStatus();
        String newService = tmcOrderDTO.getAttributes().get("newService");

        // 新单（新接口）
        if ("true".equals(newService)) {
            saveNewOrder(tmcOrderDTO, message, true);
        }
        // 新单（旧接口）
        else if (Objects.equals(taskStatus, TaobaoTmcConstants.ORDER_TASK_STATUS_NEW_ORDER)) {
            saveNewOrder(tmcOrderDTO, message, false);
        }
        // 取消订单
        else if (Objects.equals(taskStatus, TaobaoTmcConstants.ORDER_TASK_STATUS_ORDER_CANCEL)) {
            cancelOrder(tmcOrderDTO, message);
        }
        // 其他状态不做处理
        else {
            logger.info("【{}-消息-订单】非新单消息数据（已忽略） TaskStatus:[{}]",
                    TaobaoTmcConstants.NAME_TMALL_QG, taskStatus);
        }
    }

    /**
     * 处理天猫B端安装订单消息
     */
    private void procMsg4TmallBusiness(TmcOrderDTO tmcOrderDTO, Message message) throws Exception {
        /*                  分析推送过来的订单的状态                       */
        /* 当订单信息（状态）发生变化时，淘宝会将最新订单信息推送过来（包括   */
        /* 通过接口给淘宝同步订单状态引起的订单状态改变），所以需依靠状态字段 */
        /* （taskStatus）来区分出该订单消息的业务类型（主要提取新单消息和顾客 */
        /* 主动取消订单消息）                                              */
        /*                       状态码说明                               */
        /* 服务：sendAndInstall                                              */
        /* 状态：-1:商品已发货；1:商品已签收；3:服务已预约；5:服务已完成；   */
        /*      11:服务已取消；12:服务已取消（退款）                        */
        /* 完结状态：5, 11, 12                                             */
        int taskStatus = Optional.ofNullable(tmcOrderDTO.getTaskStatus()).orElse(-10000);
        String newService = tmcOrderDTO.getAttributes().get("newService");

        // 新单（新接口）
        if ("true".equals(newService)) {
            saveNewOrder(tmcOrderDTO, message, true);
        }
        // 新单（旧接口）
        else if (taskStatus == -1 || taskStatus == 1 || taskStatus == 3) {
            saveNewOrder(tmcOrderDTO, message, false);
        }
        // 取消订单
        else if (taskStatus == 11 || taskStatus == 12) {
            cancelOrder(tmcOrderDTO, message);
        }
        // 其他状态不做处理
        else {
            logger.info("【{}-消息-订单】非新单消息数据（已忽略） TaskStatus:[{}]",
                    TaobaoTmcConstants.NAME_TMALL_BIZ, taskStatus);
        }
    }

    // 保存新单
    private void saveNewOrder(TmcOrderDTO tmcOrderDTO, Message message, boolean isNewService) throws Exception {
        /*                                      outerId                                          */
        /* 一个淘宝订单中可以申请多次服务，"parentBizOrderId"字段为淘宝订单ID，"id"字段为服务订单ID。*/
        /* 每个服务订单对应一个啄木鸟订单，为了能区分出同一个淘宝订单中的不同服务订单，此处使用了服务  */
        /* 订单ID作为outerId，给淘宝同步状态使用的是服务订单ID。                                    */
        String outerId = Long.toString(tmcOrderDTO.getId());

        // 校验是不是重复的订单消息
        if (isDuplicateClue(outerId)) {
            logger.info("【{}-消息-订单】重复的消息数据（已忽略） OuterId:[{}]", TaobaoTmcConstants.NAME_TMALL, outerId);
            return;
        }

        /* 区分服务分类（目前只支持家电安装业务） */
        /* 按服务分类不同生成工单对象            */
        String serviceCode = tmcOrderDTO.getServiceCode();
        CreateOrderDTO createOrderDTO = null;
        // 默认渠道：天猫勤鸽店
        String channelName = TaobaoTmcConstants.NAME_TMALL_QG;
        int channelId = OrderConsts.CHANNEL_ID_TMALL_WYG;

        // 家电维修安装-天猫无忧购
        if (TaobaoTmcConstants.SERVICE_APPLIANCE_REPAIR.equals(serviceCode)
                || TaobaoTmcConstants.SERVICE_AIR_CONDITIONER_INSTALL.equals(serviceCode)
                || TaobaoTmcConstants.SERVICE_WATER_PURIFIER_INSTALL_REPLACE.equals(serviceCode)) {
            createOrderDTO = buildOrderDTO4Install(tmcOrderDTO, channelId);
        }
        // 家电清洗-天猫无忧购
        else if (TaobaoTmcConstants.SERVICE_APPLIANCE_CLEANING.equals(serviceCode)
                || TaobaoTmcConstants.SERVICE_AIR_CONDITIONER_CLEANING.equals(serviceCode)) {
            createOrderDTO = buildOrderDTO4Clean(tmcOrderDTO, channelId);
        }
        // 家电安装-天猫B端安装
        else if (TaobaoTmcConstants.SERVICE_SEND_AND_INSTALL.equals(serviceCode)
                || TaobaoTmcConstants.SERVICE_TV_INSTALL.equals(serviceCode)
                || TaobaoTmcConstants.SERVICE_APPLIANCE_INSTALL.equals(serviceCode)) {
            channelId = TaobaoMapper.getChannelIdBySellerId(tmcOrderDTO.getSellerId());
            channelName = TaobaoTmcConstants.NAME_TMALL_BIZ;

            createOrderDTO = buildOrderDTO4Install(tmcOrderDTO, channelId);
        }
        else {
            logger.info("【{}-消息-订单】发现未知的服务类型，已识别成维修类型 ServiceCode:[{}]",
                    TaobaoTmcConstants.NAME_TMALL, serviceCode);

            /*
                加入清洗单的智能判断逻辑，解决天猫新加的清洗单产品无法识别的问题  2020.11.11 by lhl
                清洗单产品无法识别，默认会识别成维修，而维修会把订单下单到言而有信的平台，识别成保内单
             */
            String cleanRegex = ".*?(?:_clean(?:ing)?|QINGXI).*?";
            if (Pattern.matches(cleanRegex, serviceCode)) {
                createOrderDTO = buildOrderDTO4Clean(tmcOrderDTO, channelId);
            }
            else {
                createOrderDTO = buildOrderDTO4Install(tmcOrderDTO, channelId);
            }
        }

        // 保存订单
        if (createOrderDTO != null) {
            createOrderDTO.setOuterData(message.getContent());
            createOrderDTO.setChannelId(channelId);

            // 针对天猫B端订单，修正价格等数据
            fillOrderInfo4TmallBusiness(createOrderDTO, tmcOrderDTO);

            // 地址解析失败时，默认地址写重庆，产品设置为其他，避免自动派单
            if (createOrderDTO.getCityId() == null) {
                ThirdOrderUtil.fillDefaultOrderInfo(createOrderDTO, "；地址未能自动识别，需人工确认");
            }

            OrderBO orderBO = proxyOrderBService.createOrder(createOrderDTO);
            OrderWork orderWork = orderBO.getOrderWork();

            logger.info("【{}-消息-订单】保存订单成功 OrderId:[{}]", channelName, orderWork.getOrderId());

            try {
                // 添加工程师签到&核销原始数据
                initMasterSignInData(tmcOrderDTO, orderWork, isNewService);

                // 工单自动流转
                workFlowContextBService.asyncAutoFlow(orderWork.getOrderId(),orderWork.getWorkId());

                // 添加回复预约时间任务：5分钟后给天猫同步预约时间
                addReplyDutyTimeJob(orderWork.getOrderId());
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    // 取消订单
    private void cancelOrder(TmcOrderDTO tmcOrderDTO, Message message) {
        /*                  处理顾客在淘宝客户端主动取消订单的消息                       */
        /* 取消订单消息分两种：1.顾客在淘宝客户端主动取消订单的消息；2.我们自己取消订单后， */
        /* 会通过接口同步给淘宝，淘宝会再次给我们发送取消订单消息，通知我们该订单已取消。   */
        /* 针对第二种情况我们不做处理，只处理第一种情况，即：顾客主动取消订单后，需将系统中 */
        /* 的订单变更为已取消状态 */

        // 排除非顾客主动取消订单消息
        // 判断是不是顾客主动取消订单，可通过查看系统中订单的结果状态是不是“进行中”获知
        String outerId = Long.toString(tmcOrderDTO.getId());
        ZsOrderWorkVO orderWork = queryOrderByOuterId(outerId);
        if (orderWork == null) {
            logger.error("【{}-消息-订单】处理取消订单消息时发生错误，系统中不存在对应的订单！ OuterId:[{}]",
                    TaobaoTmcConstants.NAME_TMALL, outerId);
            return;
        }
        if (!Objects.equals(OrderStatusConsts.WORK_RESULT_DOING, orderWork.getResultStatus())) {
            logger.info("【{}-消息-订单】非新单消息数据（已忽略） TaskStatus:[{}]",
                    TaobaoTmcConstants.NAME_TMALL, tmcOrderDTO.getTaskStatus());
            return;
        }
        logger.info("【{}-消息-订单】顾客取消订单消息数据 TaskStatus:[{}]",
                TaobaoTmcConstants.NAME_TMALL, tmcOrderDTO.getTaskStatus());

        // 取消订单
        try {
            CancelOrderDTO cancelOrderDTO = new CancelOrderDTO();
            cancelOrderDTO.setChannelId(orderWork.getChannelId());
            cancelOrderDTO.setOrderId(orderWork.getOrderId());
            cancelOrderDTO.setRemark("顾客取消订单");
            cancelOrderDTO.setOuterData(JSON.toJSONString(tmcOrderDTO));
            proxyOrderBService.cancelOrder(cancelOrderDTO);
        } catch (OmsBaseException e) {
            // 捕获异常，不抛出方法外，不然会触发消息重发，
            // 此处处理失败，忽略取消操作
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 将天猫订单数据转换成录单对象：安装业务订单
     * @param tmcOrderDTO
     * @return
     */
    private CreateOrderDTO buildOrderDTO4Install(TmcOrderDTO tmcOrderDTO, Integer channelId) {
        CreateOrderDTO createOrderDTO = _buildOrderDTO(tmcOrderDTO, GlobalConsts.SERV_CATEG_INSTALL, channelId);

        return createOrderDTO;
    }

    /**
     * 将天猫订单数据转换成录单对象：清洗业务订单
     * @param tmcOrderDTO
     * @return
     */
    private CreateOrderDTO buildOrderDTO4Clean(TmcOrderDTO tmcOrderDTO, Integer channelId) {
        CreateOrderDTO createOrderDTO = _buildOrderDTO(tmcOrderDTO, GlobalConsts.SERV_CATEG_CLEAN, channelId);

        // 用户在天猫侧支付全款（订单收入 = 渠道预付）
        createOrderDTO.setTotalAmount(createOrderDTO.getChannelPrepayAmount());

        return createOrderDTO;
    }

    /**
     * 天猫B端安装业务工单：针对工单数据进行修正
     */
    private void fillOrderInfo4TmallBusiness(CreateOrderDTO zmnOrder, TmcOrderDTO tmcOrder) {
        if (zmnOrder == null || OrderConsts.CHANNEL_ID_TMALL_WYG == zmnOrder.getChannelId()) {
            return;
        }
        // 修正订单预付款
        String servicePriceStr = tmcOrder.getAttributes().get("servPrice"); // 消费者在线购买了安装服务，标识了服务的价格，单位分
        Integer auctionPrice = StringUtils.isBlank(servicePriceStr) ? 0 : Integer.parseInt(servicePriceStr);// 价格单位用：分
        Integer auctionCount = Optional.ofNullable(tmcOrder.getServiceCount()).orElse(1);
        zmnOrder.setChannelPrepayAmount(auctionPrice * auctionCount);
        zmnOrder.setChannelPrepayStatus(PayConsts.PAY_STATUS_DONE);

        // 修正预约时间
        String operatorStr = tmcOrder.getAttributes().get("operator");  // 1表示消费者主动预约，2表示服务商回传的预约时间
        String serviceDateStr = tmcOrder.getAttributes().get("serviceDate");    // 预约上门服务时间
        if ("1".equals(operatorStr) && StringUtils.isNotBlank(serviceDateStr)) {
            // 消费者主动预约了上门时间
            Date dutyTime = DateUtil.parse(serviceDateStr, DateUtil.FORMAT_DEFAULT);
            // 忽略掉当前时间超过预约时间的情况，由线下去确定预约时间
            if (dutyTime.getTime() > System.currentTimeMillis()) {
                zmnOrder.setDutyTime(DateUtil.round(dutyTime, DateUtil.UNIT_MINUTE));
            }
        }
        else {
            zmnOrder.setDutyTime(null); // 默认无预约时间
        }

        // 服务备注: 比如电视会标注安装方式是挂装或者座装
        String servSkuName = tmcOrder.getAttributes().get("servSkuName");
        if (StringUtils.isNotBlank(servSkuName)) {
            zmnOrder.setRemark(servSkuName);
        }

        // 天猫B端厂商结算订单，没有渠道预付款，归为保内单
        if (OrderConsts.CHANNEL_ID_TMALL_BUSINESS != zmnOrder.getChannelId()) {
            zmnOrder.setFactory(GlobalConsts.YES);
            zmnOrder.setPlat(GlobalConsts.PLAT_MARK_YEYX);
            zmnOrder.setBizType(com.zmn.consts.GlobalConsts.BIZ_TYPE_F);
            zmnOrder.setChannelPrepayAmount(0);
            zmnOrder.setChannelPrepayStatus(PayConsts.PAY_STATUS_NONE);
        }
        else {
            // 订单金额与渠道预付款之间的差额，使用优惠补齐
            zmnOrder.setChannelPrepayOnly(GlobalConsts.YES);
            {// 修正产品ID
                // 优先使用名称匹配，根据接口里面过来的产品名称映射产品ID（后台产品）
                //  >>- 若产品名称，包含有：“电视”字样，则映射产品ID：11122
                //  >>- 若产品名称，包含有：“热水器”字样，则映射产品ID：11123
                String productName = tmcOrder.getAuctionName();
                if (productName != null) {
                    if (productName.matches(".*(?:电视|彩电|液晶).*")) {
                        zmnOrder.getOrderProductList().get(0).setProductId(11122);
                    } else if (productName.contains("热水")) {
                        zmnOrder.getOrderProductList().get(0).setProductId(11123);
                    }
                }
            }
        }

    }

    /**
     * 添加回复预约时间任务
     */
    private void addReplyDutyTimeJob(Long orderId) {
        // 5分钟后，给天猫同步预约时间
        Job job = new Job();
        job.setTaskId(TaskConsts.TASK_ID_TMALL_REPLY_DUTYTIME_JOB + ":" + orderId);
        job.setParam("orderId", orderId.toString());
        job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_TMALL_REPLY_DUTYTIME_JOB);
        Date date = DateUtil.addMinute(DateUtil.getNow(), 5);
        taskManager.submitTask(job, -1, DateUtil.dateFormatToString(date, DateUtil.FORMAT_DEFAULT));
    }

    /**
     * 将天猫订单数据转换成录单对象
     * @param tmcOrderDTO
     * @return
     */
    private CreateOrderDTO _buildOrderDTO(TmcOrderDTO tmcOrderDTO, Integer servCategId, Integer channelId) {
        CreateOrderDTO createOrderDTO = new CreateOrderDTO();
        createOrderDTO.setChannelId(channelId);

        // 将同步数据中的订单关键信息记录进日志中
        createOrderDTO.setOperatorLogRemark(String.format(
                "父订单编号：%s，服务子订单：%s，服务工单号：%s，产品：%s，数量：%s，商品ID：%s，商品SKUID：%s；",
                tmcOrderDTO.getParentBizOrderId(), tmcOrderDTO.getBizOrderId(), tmcOrderDTO.getId(),
                tmcOrderDTO.getAuctionName(), tmcOrderDTO.getServiceCount(),
                tmcOrderDTO.getAuctionId(), tmcOrderDTO.getAuctionSkuid()));

        createOrderDTO.setContactName(tmcOrderDTO.getBuyerName());
        createOrderDTO.setOuterId(Long.toString(tmcOrderDTO.getId()));
        createOrderDTO.setExtOuterId(Long.toString(tmcOrderDTO.getParentBizOrderId()));
        createOrderDTO.setExtOuterSubId(Long.toString(tmcOrderDTO.getBizOrderId()));
        createOrderDTO.setRemark(tmcOrderDTO.getMemo());

        // 联系电话分buyerPhone和buyerMobile
        if (StringUtils.isNotBlank(tmcOrderDTO.getBuyerMobile())) {
            createOrderDTO.setTelephone(tmcOrderDTO.getBuyerMobile());
            createOrderDTO.setTelephone2(tmcOrderDTO.getBuyerPhone());
        }
        else {
            createOrderDTO.setTelephone(tmcOrderDTO.getBuyerPhone());
        }

        // expectDate 预约时间，注意就近转化为：整点和半点
        String expectDate = tmcOrderDTO.getExpectDate();
        if (StringUtils.isNotBlank(expectDate)) {
            Date dutyTime = DateUtil.parse(expectDate, DateUtil.FORMAT_DEFAULT);
            // 忽略掉当前时间超过预约时间的情况，由线下去确定预约时间
            if (dutyTime.getTime() > System.currentTimeMillis()) {
                createOrderDTO.setDutyTime(DateUtil.round(dutyTime, DateUtil.UNIT_MINUTE));
            }
        }

        try {
            // 地址转换
            _fillAddress(createOrderDTO, tmcOrderDTO);
            // 商品转换
            _fillProductInfo(createOrderDTO, tmcOrderDTO, servCategId);

        } catch (Exception e) {
            logger.error("【{}-消息-订单】ErrorMsg:[{}]", TaobaoTmcConstants.NAME_TMALL, e.getMessage(), e);
            return null;
        }

        createOrderDTO.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        createOrderDTO.setGender(GlobalDict.GENDER_NO);
        createOrderDTO.setDisableDiscard(GlobalConsts.NO);
        createOrderDTO.setOperator("系统");
        createOrderDTO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        createOrderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        createOrderDTO.setInputType(OrderConsts.ORDER_INPUT_TYPE_API);

        return createOrderDTO;
    }

    /**
     * 补全产品信息
     * @param zmnOrder
     * @param tmcOrder
     * @param servCategId
     */
    private void _fillProductInfo(CreateOrderDTO zmnOrder, TmcOrderDTO tmcOrder, Integer servCategId) {
        Integer productId = null;

        {// 1.产品映射库查询产品ID
            List<ChannelProductMapDTO> productMapDTOS = productMappingBService.listChannelProductMapping(
                    zmnOrder.getChannelId(), String.valueOf(tmcOrder.getAuctionId()), String.valueOf(tmcOrder.getAuctionSkuid()));
            if (CollectionUtils.isNotEmpty(productMapDTOS)) {
                productId = productMapDTOS.get(0).getProductId();
            }
        }
        if (productId == null) {
            productId = TaobaoMapper.getZmnProductId(
                    tmcOrder.getAuctionId(), tmcOrder.getAuctionSkuid(), servCategId);
        }
        OrderProductDTO orderProduct = new OrderProductDTO();
        orderProduct.setProductId(productId);
        orderProduct.setNumber(tmcOrder.getServiceCount());

        List<OrderProductDTO> list = new LinkedList<>();
        list.add(orderProduct);
        zmnOrder.setOrderProductList(list);

        // 渠道预付款: 淘宝产品价格 X 服务数量
        Integer auctionPrice = Optional.ofNullable(tmcOrder.getAuctionPrice()).orElse(0); // 价格单位用：分
        if (tmcOrder.getAttributes() != null) {
            String servicePriceStr = tmcOrder.getAttributes().get("servPrice"); // 新接口价格使用这个参数
            auctionPrice = StringUtils.isBlank(servicePriceStr) ? auctionPrice : Integer.parseInt(servicePriceStr);// 价格单位用：分
        }
        Integer auctionCount = Optional.ofNullable(tmcOrder.getServiceCount()).orElse(1);
        zmnOrder.setChannelPrepayAmount(auctionPrice * auctionCount);
        zmnOrder.setChannelPrepayStatus(PayConsts.PAY_STATUS_DONE);

        zmnOrder.setOperatorLogRemark(zmnOrder.getOperatorLogRemark() +"；产品单价："+ MoneyUtil.parseToYuanStr(auctionPrice) +"元");
    }

    // 补全订单地址：将淘宝订单地址转换成符合我们自己系统使用的地址信息
    private void _fillAddress(CreateOrderDTO orderDTO, TmcOrderDTO tmc) {
        // buyerAddress格式中，省、市、区用空格分隔，例如：浙江省 宁波市 海曙区 石碶街道雅戈尔大道243号
        String buyerAddress = tmc.getBuyerAddress();
        String[] arr = buyerAddress.split(" ");
        {
            /*
                地址信息偶尔会有下面结构的数据，导致经纬度无法解析，需特殊处理一下
                江苏省 苏州市 张家港市 张家港经济技术开发区 张家港经济技术开发区江苏省张家港市塘市镇西溪花园9栋
                江苏省 扬州市 邗江区 邗上街道 邗上街道江苏省扬州市邗江区文昌西路248号翠岗小区白兰苑11栋509室菜鸟驿站
             */
            if (arr.length == 5) {
                String arr5 = arr[4];
                // 第一次去重
                String arr4arr1 = arr[3] + arr[0];
                if (arr5.startsWith(arr4arr1)) {
                    arr5 = arr5.replaceFirst(arr4arr1, "");
                }
                // 第二次去重
                String arr2arr3 = arr[1] + arr[2];
                if (arr5.startsWith(arr2arr3)) {
                    arr5 = arr5.replaceFirst(arr2arr3, "");
                }
                // 第三次去重
                String arr2 = arr[1];
                if (arr5.startsWith(arr2)) {
                    arr5 = arr5.replaceFirst(arr2, "");
                }
                // 第四次去重
                String arr3 = arr[2];
                if (arr5.startsWith(arr3)) {
                    arr5 = arr5.replaceFirst(arr3, "");
                }
                arr[4] = arr5;
            }
        }

        // 具体地址放入address
        orderDTO.setAddress(arr[arr.length - 1]);
        orderDTO.setStreet(""); // street字段在数据库中不能为空

        // 通过地址获取经纬度
        StringBuilder addressBuilder = new StringBuilder();
        for (int i=0, len=arr.length; i<len; i++) {
            addressBuilder.append(arr[i]);
        }
        String addressStr = addressBuilder.toString();
        LngLatLocation location = baiduMapBService.location(addressStr);
        if (location != null) {
            orderDTO.setLatitude(Double.valueOf(location.getLat()));
            orderDTO.setLongitude(Double.valueOf(location.getLng()));
        }
        else {
           logger.info("获取经纬度失败：address=[{}]", addressStr);
        }

        // 获取cityId：如果有经纬度，以经纬度获取城市为准；
        if (orderDTO.getLongitude() != null && orderDTO.getLatitude() != null) {
            try {
                ResponseDTO<com.zmn.base.common.data.common.dro.area.AreaDRO> areaResponse = areaListRemoteService.getAreaByLatAndLng(orderDTO.getLongitude(), orderDTO.getLatitude());
                AreaDRO areaDRO = areaResponse.getData();
                if (areaDRO != null) {
                    orderDTO.setCityId(areaDRO.getParentId());
                }
                else {
                    logger.info("解析经纬度失败：lng=[{}], lat=[{}], ResponseDTO=[{}]",
                            String.valueOf(orderDTO.getLongitude()), String.valueOf(orderDTO.getLatitude()), JSON.toJSONString(areaResponse));
                }
            } catch (Exception e) {
                logger.error("【{}-消息-订单】使用经纬度获取CityId失败:[{}]", TaobaoTmcConstants.NAME_TMALL, e.getMessage(), e);
            }
        }
        // 获取cityId：无法以经纬度获取城市，使用天猫给的地址编码获取城市
        if (orderDTO.getCityId() == null) {
            MapCityTmall cityMap = mapCityTmallService.findMapCityTmallByTmStreetIdOrCountyId(tmc.getBuyerLocation());
            if (cityMap != null && cityMap.getZmnCityId() != null) {
                orderDTO.setCityId(cityMap.getZmnCityId());
            }
        }

        // 记录一下完整地址
        orderDTO.setOperatorLogRemark(orderDTO.getOperatorLogRemark() + addressStr);
    }

    /**
     * 初始化天猫信息表
     */
    private void initMasterSignInData(TmcOrderDTO tmcOrderDTO,OrderWork orderWork, boolean isNewService ) {
        String vipOrder = tmcOrderDTO.getAttributes().get("vipOrder");
        String bigPromotionOrder = tmcOrderDTO.getAttributes().get("bigPromotionOrder");

        OrderTmallExtendDTO orderTmallExtendDTO = new OrderTmallExtendDTO();
        orderTmallExtendDTO.setOrderId(orderWork.getOrderId());
        orderTmallExtendDTO.setOuterId(orderWork.getOuterId());
        orderTmallExtendDTO.setChannelId(orderWork.getChannelId());
        orderTmallExtendDTO.setCreateTime(new Date());
        orderTmallExtendDTO.setSignInStatus(GlobalConsts.NONE);
        orderTmallExtendDTO.setVisitEarlyFlag(GlobalConsts.NONE);
        orderTmallExtendDTO.setVerification(isNewService ? GlobalConsts.NONE : GlobalConsts.YES);
        orderTmallExtendDTO.setServiceCode(tmcOrderDTO.getServiceCode());
        orderTmallExtendDTO.setServiceCount(tmcOrderDTO.getServiceCount());

        // vip标识
        if ("true".equals(vipOrder)) {
            orderTmallExtendDTO.setVipOrder(GlobalConsts.YES);
        }

        // 大促标识
        if ("true".equals(bigPromotionOrder)) {
            orderTmallExtendDTO.setBigPromotionOrder(GlobalConsts.YES);
        }

        // 管道疏通不走勤鸽APP
        if (Objects.equals(orderWork.getServCategId(), GlobalConsts.SERV_CATEG_PIPE)) {
            orderTmallExtendDTO.setVerification(GlobalConsts.YES);
        }

        try {
            orderTmallExtendBService.saveOrderTmallExtendWithOutLog(orderTmallExtendDTO);
        } catch (Exception e) {
            logger.info("【{}-订单】保存天猫表信息信息失败 MasterSignInDTO:[{}]",
                    TaobaoTmcConstants.NAME_TMALL, JSON.toJSONString(orderTmallExtendDTO));
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 判断是否是重复的新单消息, 如果是重复消息，返回true
     * @param outerId
     * @return
     */
    private boolean isDuplicateClue(String outerId) {
        /*
         * 天猫新单消息去重需要做两方面处理：
         *  1. 天猫订单在接单后几天内，还是有可能推该单的新单消息，针对这种情况，通过outerId查看数据库中是否有该订单，判断其是否为重复；
         *  2. 第一次收到新单消息时，有可能在间隔不超过一秒的时间内，收到该单的重复推送消息，此时该订单的第一条消息还没有入库，所以
         *      第二条消息在采用1中的去重逻辑时无法识别为重复消息，需要采用redis计数器判断该订单在5分钟内是否重复收到过，得出是否为
         *      重复消息；
         */
        // 方案1去重
        ZsOrderWorkVO orderWork = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(outerId,
                Lists.newArrayList(
                        OrderConsts.CHANNEL_ID_TMALL_WYG,
                        OrderConsts.CHANNEL_ID_TMALL_BUSINESS,
                        OrderConsts.CHANNEL_ID_TMALL_BIZ_OPPEIN,
                        OrderConsts.CHANNEL_ID_TMALL_BIZ_LAIMD,
                        OrderConsts.CHANNEL_ID_TMALL_PIPE)
        );
        if (orderWork != null) {
            return true;
        }

        // 方案2去重
        String redisKey = String.format(RedisKeyConsts.TMALL_REDIS_KEY_CLUE_ID, outerId);
        Long incr = redisManager.incr(redisKey);

        if (incr.intValue() > 1) {
            return true;
        }

        // 设置自动过期，清除Redis占用
        redisManager.expire(redisKey, TaobaoTmcConstants.REDIS_EXPIRE_SECONDS);

        return false;
    }
}
